use chardetng::EncodingDetector;
use clap::Parser;
use std::{self, path::Path, process::exit};

/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
    #[arg(short('i'), long, help("原始路径"))]
    input: String,

    #[arg(short('o'), long, help("输出路径"))]
    output: String,

    #[arg(help("文件后缀列表"))]
    suffix: Vec<String>,
}

fn main() {
    let args = Args::parse();

    let mut suffix_list: Vec<String> = args.suffix;

    check_folder_valid(&args.input, &args.output);

    extend_suffix_list(&mut suffix_list);

    let file_list = get_file_list(&args.input, &suffix_list);
    let src_dest_file_list = convert_path(&args.input, &args.output, &file_list);

    convert_files(src_dest_file_list);
}

fn check_folder_valid(input: &String, output: &String) {
    if std::fs::metadata(input).is_err() {
        println!("输入文件夹不存在");
        exit(-1);
    }
    if std::fs::metadata(output).is_err() {
        // 输出文件夹不存在
        println!("输出文件夹{}不存在，尝试创建", output);
        // 创建输出文件夹
        if std::fs::create_dir(output).is_err() {
            println!("输出文件夹{}不存在，且创建失败", output);
            exit(-1);
        }
    }
}

fn extend_suffix_list(suffix_list: &mut Vec<String>) {
    for suffix in suffix_list.clone().iter_mut() {
        // 以点开始
        if suffix.starts_with(".") {
            suffix_list.retain(|elem| *elem != *suffix);

            suffix.retain(|c| c != '.');
        }
        let upper = suffix.to_ascii_uppercase();
        let lower = suffix.to_ascii_lowercase();
        if !suffix_list.contains(&upper) {
            suffix_list.push(upper);
        }
        if !suffix_list.contains(&lower) {
            suffix_list.push(lower);
        }
    }
}

fn get_file_list(input_dir: &String, suffix_list: &Vec<String>) -> Vec<String> {
    let mut file_list = Vec::<String>::with_capacity(80);

    fn recursive_get_file_list(path: &str, file_list: &mut Vec<String>, suffix_list: &Vec<String>) {
        if let Ok(entries) = std::fs::read_dir(path) {
            for entry in entries {
                if let Ok(entry) = entry {
                    let entry_path = entry.path();
                    if entry_path.is_file() {
                        let extention = entry_path
                            .extension()
                            .unwrap()
                            .to_str()
                            .unwrap()
                            .to_string();
                        if suffix_list.contains(&extention) {
                            file_list.push(entry_path.to_str().unwrap().to_string());
                        } else {
                            println!("过滤文件：{}", entry_path.to_str().unwrap());
                        }
                    } else if entry_path.is_dir() {
                        recursive_get_file_list(
                            entry_path.to_str().unwrap(),
                            file_list,
                            suffix_list,
                        );
                    }
                }
            }
        } else {
            panic!("文件夹读取失败");
        }
    }
    recursive_get_file_list(input_dir, &mut file_list, suffix_list);
    file_list
}

fn convert_path(
    src_path: &String,
    dest_path: &String,
    file_list: &Vec<String>,
) -> Vec<(String, String)> {
    let mut ret = Vec::<(String, String)>::with_capacity(file_list.capacity());
    for file_path in file_list.iter() {
        ret.push((file_path.clone(), file_path.replace(src_path, &dest_path)));
    }
    ret
}

fn convert_files(file_list: Vec<(String, String)>) {
    for (src_file, dest_file) in file_list.iter() {
        let dest_path = Path::new(dest_file).parent().unwrap();
        std::fs::create_dir_all(dest_path).expect("文件夹创建出错");

        let mut content = std::fs::read(src_file).unwrap();
        //转换编码
        // 识别原来的编码
        let mut detector = EncodingDetector::new();
        detector.feed(content.as_slice(), true);
        let charset = detector.guess(None, true);
        // 重新编码
        let string_content = charset.decode(content.as_mut()).0;

        content = (encoding_rs::UTF_8.encode(&string_content).0.as_ref()).to_vec();
        // 保存到新的文件
        std::fs::write(dest_file, content).unwrap();
        println!("{} => {}, encoding={}", src_file, dest_file, charset.name());
    }
}

#[test]
fn test_convert() {
    let args = Args {
        input: String::from(r"C:\Users\Administrator\Desktop\MT300X_V1_1_20200715"),
        output: String::from(r"C:\Users\Administrator\Desktop\MT300X_V1_1_202230210"),
        suffix: [".c", ".h", ".asm", ".s"].map(String::from).to_vec(),
    };

    let mut suffix_list: Vec<String> = args.suffix;

    check_folder_valid(&args.input, &args.output);

    extend_suffix_list(&mut suffix_list);

    let file_list = get_file_list(&args.input, &suffix_list);
    let src_dest_file_list = convert_path(&args.input, &args.output, &file_list);

    convert_files(src_dest_file_list);
}

#[test]
fn test_extend_suffix_list() {
    let mut suffix_list = vec![".c".to_string(), ".s".to_string()];
    extend_suffix_list(&mut suffix_list);
    println!("suffix: {:?}", suffix_list);
}

#[test]
fn test_get_file_list() {
    let input = String::from(r"C:\Users\Administrator\Desktop\MT300X_V1_1_20200715");
    let mut suffix_list = [".c", ".s", ".h", ".asm"].map(String::from).to_vec();
    extend_suffix_list(&mut suffix_list);
    println!("suffix: {:?}", suffix_list);
    let file_list = get_file_list(&input, &suffix_list);
    println!("file list: {:?}", file_list);
}
